home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / programming / ixemul-complete / ixemul / libsrc / gmon.c < prev    next >
C/C++ Source or Header  |  1996-08-13  |  9KB  |  336 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #include <unistd.h>
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <sys/fcntl.h>
  40.  
  41. #include "gmon.h"
  42.  
  43. extern void mcount(void) asm ("mcount");
  44. extern void start_text () asm ("exec");
  45.  
  46. void moncontrol(int mode);
  47.  
  48. static unsigned int    *store_last_pc;
  49. static unsigned int    dummy;
  50.     /*
  51.      *    froms is actually a bunch of unsigned shorts indexing tos
  52.      */
  53. static int        profiling = 3;
  54. static unsigned short    *froms;
  55. static struct tostruct    *tos = 0;
  56. static long        tolimit = 0;
  57. static char        *s_lowpc = 0;
  58. static char        *s_highpc = 0;
  59. static unsigned long    s_textsize = 0;
  60.  
  61. static int    ssiz;
  62. static char    *sbuf;
  63. static int    s_scale;
  64.     /* see profil(2) where this is describe (incorrectly) */
  65. #define        SCALE_1_TO_1    0x10000L
  66.  
  67. #define    MSG "No space for profiling buffer(s)\n"
  68.  
  69. static inline void *
  70. alloc(int s)
  71. {
  72.   void *res = malloc (s);
  73.   if (res)
  74.     bzero (res, s);
  75.   return res;
  76. }
  77.  
  78. void monstartup(char *lowpc, char *highpc)
  79. {
  80.     int            monsize;
  81.     char        *buffer;
  82.     register int    o;
  83.  
  84.     /*
  85.      *    round lowpc and highpc to multiples of the density we're using
  86.      *    so the rest of the scaling (here and in gprof) stays in ints.
  87.      */
  88.     lowpc = (char *)
  89.         ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
  90.     s_lowpc = lowpc;
  91.     highpc = (char *)
  92.         ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
  93.     s_highpc = highpc;
  94.     s_textsize = highpc - lowpc;
  95.     monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
  96.     buffer = alloc( monsize );
  97.     if ( buffer == 0 ) {
  98.     write( 2 , MSG , sizeof(MSG) );
  99.     return;
  100.     }
  101.     froms = (unsigned short *) alloc ( s_textsize / HASHFRACTION );
  102.     if ( froms == 0 ) {
  103.     write( 2 , MSG , sizeof(MSG) );
  104.     froms = 0;
  105.     return;
  106.     }
  107.     tolimit = s_textsize * ARCDENSITY / 100;
  108.     if ( tolimit < MINARCS ) {
  109.     tolimit = MINARCS;
  110.     } else if ( tolimit > 65534 ) {
  111.     tolimit = 65534;
  112.     }
  113.     tos = (struct tostruct *) alloc( tolimit * sizeof( struct tostruct ) );
  114.     if ( tos == 0 ) {
  115.     write( 2 , MSG , sizeof(MSG) );
  116.     froms = 0;
  117.     tos = 0;
  118.     return;
  119.     }
  120.     tos[0].link = 0;
  121.     sbuf = buffer;
  122.     ssiz = monsize;
  123.     ( (struct phdr *) buffer ) -> lpc = (void *)(lowpc - ((char *)start_text - 4));
  124.     ( (struct phdr *) buffer ) -> hpc = (void *)(highpc - ((char *)start_text - 4));
  125.     ( (struct phdr *) buffer ) -> ncnt = ssiz;
  126.     monsize -= sizeof(struct phdr);
  127.     if ( monsize <= 0 )
  128.     return;
  129.     o = highpc - lowpc;
  130.     if( monsize < o )
  131.     {
  132.     int quot = o / monsize;
  133.  
  134.     if (quot >= 0x10000)
  135.         s_scale = 1;
  136.     else if (quot >= 0x100)
  137.         s_scale = 0x10000 / quot;
  138.     else if (o >= 0x800000)
  139.         s_scale = 0x1000000 / (o / (monsize >> 8));
  140.     else
  141.         s_scale = 0x1000000 / ((o << 8) / monsize);
  142.     }
  143.     else
  144.     s_scale = SCALE_1_TO_1;
  145.     moncontrol(1);
  146. }
  147.  
  148. void _mcleanup(void)
  149. {
  150.     int            fd;
  151.     int            fromindex;
  152.     int            endfrom;
  153.     char        *frompc;
  154.     int            toindex;
  155.     struct rawarc    rawarc;
  156.  
  157.     moncontrol(0);
  158.     fd = creat( "gmon.out" , 0666 );
  159.     if ( fd < 0 ) {
  160.     perror( "mcount: gmon.out" );
  161.     return;
  162.     }
  163. #   ifdef DEBUG
  164.     fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
  165. #   endif DEBUG
  166.     write( fd , sbuf , ssiz );
  167.     endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
  168.     for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
  169.     if ( froms[fromindex] == 0 ) {
  170.         continue;
  171.     }
  172.     frompc = (void *)(s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)) - ((char *)start_text - 4));
  173.     for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
  174. #        ifdef DEBUG
  175.         fprintf( stderr ,
  176.             "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
  177.             frompc , tos[toindex].selfpc , tos[toindex].count );
  178. #        endif DEBUG
  179.         rawarc.raw_frompc = (unsigned long) frompc;
  180.         rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
  181.         rawarc.raw_count = tos[toindex].count;
  182.         write( fd , &rawarc , sizeof rawarc );
  183.     }
  184.     }
  185.     close( fd );
  186. }
  187.  
  188. void mcount(void)
  189. {
  190.     register char            *selfpc;
  191.     register unsigned short        *frompcindex;
  192.     register struct tostruct    *top;
  193.     register struct tostruct    *prevtop;
  194.     register long            toindex;
  195.  
  196.     /*
  197.      *    find the return address for mcount,
  198.      *    and the return address for mcount's caller.
  199.      */
  200.  
  201.     /* selfpc = pc pushed by mcount call.
  202.        This identifies the function that was just entered.  */
  203.     selfpc = (char *) __builtin_return_address (0);
  204.     /* frompcindex = pc in preceding frame.
  205.        This identifies the caller of the function just entered.  */
  206.     frompcindex = (void *) __builtin_return_address (1);
  207.     /*
  208.      *    check that we are profiling
  209.      *    and that we aren't recursively invoked.
  210.      */
  211.     if (profiling) {
  212.         goto out;
  213.     }
  214.     profiling++;
  215.     *store_last_pc = (unsigned)selfpc;
  216.     selfpc = selfpc - (int)((char *)start_text - 4);
  217.     /*
  218.      *    check that frompcindex is a reasonable pc value.
  219.      *    for example:    signal catchers get called from the stack,
  220.      *            not from text space.  too bad.
  221.      */
  222. #ifdef DEBUG
  223.         fprintf (stderr, "from $%lx, self $%lx (low = $%lx)\n",
  224.              frompcindex, selfpc, s_lowpc);
  225. #endif
  226.     frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
  227.     if ((unsigned long)frompcindex > s_textsize) {
  228.  
  229.         goto done;
  230.     }
  231.     frompcindex =
  232.         &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
  233.     toindex = *frompcindex;
  234.     if (toindex == 0) {
  235.         /*
  236.          *    first time traversing this arc
  237.          */
  238.         toindex = ++tos[0].link;
  239.         if (toindex >= tolimit) {
  240.             goto overflow;
  241.         }
  242.         *frompcindex = toindex;
  243.         top = &tos[toindex];
  244.         top->selfpc = selfpc;
  245.         top->count = 1;
  246.         top->link = 0;
  247.         goto done;
  248.     }
  249.     top = &tos[toindex];
  250.     if (top->selfpc == selfpc) {
  251.         /*
  252.          *    arc at front of chain; usual case.
  253.          */
  254.         top->count++;
  255.         goto done;
  256.     }
  257.     /*
  258.      *    have to go looking down chain for it.
  259.      *    top points to what we are looking at,
  260.      *    prevtop points to previous top.
  261.      *    we know it is not at the head of the chain.
  262.      */
  263.     for (; /* goto done */; ) {
  264.         if (top->link == 0) {
  265.             /*
  266.              *    top is end of the chain and none of the chain
  267.              *    had top->selfpc == selfpc.
  268.              *    so we allocate a new tostruct
  269.              *    and link it to the head of the chain.
  270.              */
  271.             toindex = ++tos[0].link;
  272.             if (toindex >= tolimit) {
  273.                 goto overflow;
  274.             }
  275.             top = &tos[toindex];
  276.             top->selfpc = selfpc;
  277.             top->count = 1;
  278.             top->link = *frompcindex;
  279.             *frompcindex = toindex;
  280.             goto done;
  281.         }
  282.         /*
  283.          *    otherwise, check the next arc on the chain.
  284.          */
  285.         prevtop = top;
  286.         top = &tos[top->link];
  287.         if (top->selfpc == selfpc) {
  288.             /*
  289.              *    there it is.
  290.              *    increment its count
  291.              *    move it to the head of the chain.
  292.              */
  293.             top->count++;
  294.             toindex = prevtop->link;
  295.             prevtop->link = top->link;
  296.             top->link = *frompcindex;
  297.             *frompcindex = toindex;
  298.             goto done;
  299.         }
  300.  
  301.     }
  302. done:
  303.     profiling--;
  304.     /* and fall through */
  305. out:
  306.     return;        /* normal return restores saved registers */
  307.  
  308. overflow:
  309.     profiling++; /* halt further profiling */
  310. #   define    TOLIMIT    "mcount: tos overflow\n"
  311.     write(2, TOLIMIT, sizeof(TOLIMIT));
  312.     goto out;
  313. }
  314.  
  315. /*
  316.  * Control profiling
  317.  *    profiling is what mcount checks to see if
  318.  *    all the data structures are ready.
  319.  */
  320. void moncontrol(int mode)
  321. {
  322.     if (mode) {
  323.     /* start */
  324.     store_last_pc = (unsigned *)profil(sbuf + sizeof(struct phdr),
  325.                    ssiz - sizeof(struct phdr), (int)s_lowpc, s_scale);
  326.         if (store_last_pc == NULL)
  327.             store_last_pc = &dummy;
  328.     profiling = 0;
  329.     } else {
  330.     /* stop */
  331.     profil((char *)0, 0, 0, 0);
  332.     profiling = 3;
  333.     }
  334. }
  335.  
  336.